package com.xiaohua.system.controller;

import com.xiaohua.common.core.domain.R;
import com.xiaohua.system.dto.AvatarDTO;
import com.xiaohua.system.dto.LoginUserDTO;
import com.xiaohua.system.dto.MobileDTO;
import com.xiaohua.system.dto.MobileVerifyDTO;
import com.xiaohua.system.dto.WechatLoginDTO;
import com.xiaohua.common.annotation.Anonymous;
import com.xiaohua.common.core.domain.model.LoginUser;
import com.xiaohua.framework.web.service.TokenService;
import com.xiaohua.system.tool.FileTool;
import com.xiaohua.system.tool.MobileTool;
import com.xiaohua.system.tool.UserTool;
import com.xiaohua.system.tool.VerificationCodeTool;
import com.xiaohua.common.utils.ip.IpUtils;
import com.xiaohua.common.utils.ServletUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xiaohua.common.annotation.Log;
import com.xiaohua.common.core.controller.BaseController;
import com.xiaohua.common.core.domain.AjaxResult;
import com.xiaohua.common.enums.BusinessType;
import com.xiaohua.system.domain.XhUsers;
import com.xiaohua.system.service.IXhUsersService;
import com.xiaohua.common.utils.poi.ExcelUtil;
import com.xiaohua.common.core.page.TableDataInfo;

/**
 * 用户管理Controller
 * <p>
 * 提供以下功能：
 * 1. 用户注册：支持用户名密码注册、手机号验证码注册、微信登录自动注册
 * 2. 用户登录：支持用户名密码登录、手机号验证码登录、微信登录
 * 3. 用户资料：查询、修改用户资料，上传头像
 *
 * @author 小花
 * @date 2025-03-22
 */
@Api(tags = "用户管理")
@RestController
@RequestMapping("/system/users")
public class XhUsersController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(XhUsersController.class);

    @Autowired
    private IXhUsersService xhUsersService;

    @Autowired
    private TokenService tokenService;

    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * 查询用户管理列表
     */
    @PreAuthorize("@ss.hasPermi('system:users:list')")
    @GetMapping("/list")
    public TableDataInfo list(XhUsers xhUsers) {
        startPage();
        List<XhUsers> list = xhUsersService.selectXhUsersList(xhUsers);
        log.info("【用户查询】检索到 {} 条记录", list.size());
        return getDataTable(list);
    }

    /**
     * 导出用户管理列表
     */
    @PreAuthorize("@ss.hasPermi('system:users:export')")
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, XhUsers xhUsers) {
        List<XhUsers> list = xhUsersService.selectXhUsersList(xhUsers);
        log.info("【用户导出】导出 {} 条记录", list.size());
        ExcelUtil<XhUsers> util = new ExcelUtil<XhUsers>(XhUsers.class);
        util.exportExcel(response, list, "用户管理数据");
    }

    /**
     * 获取用户管理详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:users:query')")
    @GetMapping(value = "/{userId}")
    public AjaxResult getInfo(@PathVariable("userId") Long userId) {
        XhUsers user = xhUsersService.selectXhUsersByUserId(userId);
        if (user != null) {
            // 为了便于编辑，设置一个默认的明文密码提示
            user.setPassword("******"); // 使用占位符替代加密密码
            log.info("【用户详情】用户ID: {}, 用户名: {}", userId, user.getUsername());
        } else {
            log.warn("【用户详情】用户ID: {} 不存在", userId);
        }
        return success(user);
    }

    /**
     * 新增用户管理
     */
    @PreAuthorize("@ss.hasPermi('system:users:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody XhUsers xhUsers) {
        // 对密码进行加密处理
        if (xhUsers.getPassword() != null && !xhUsers.getPassword().isEmpty()) {
            xhUsers.setPassword(passwordEncoder.encode(xhUsers.getPassword()));
        }
        int result = xhUsersService.insertXhUsers(xhUsers);
        log.info("【用户新增】用户名: {}, 结果: {}", xhUsers.getUsername(), result > 0 ? "成功" : "失败");
        return toAjax(result);
    }

    /**
     * 修改用户管理
     */
    @PreAuthorize("@ss.hasPermi('system:users:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody XhUsers xhUsers) {
        // 对密码进行加密处理
        if (xhUsers.getPassword() != null && !xhUsers.getPassword().isEmpty()) {
            // 如果是占位符密码，保留原密码
            if ("******".equals(xhUsers.getPassword())) {
                XhUsers original = xhUsersService.selectXhUsersByUserId(xhUsers.getUserId());
                if (original != null) {
                    xhUsers.setPassword(original.getPassword());
                }
            }
            // 否则认为是新明文密码，进行加密
            else if (!xhUsers.getPassword().startsWith("$2a$")) {
                xhUsers.setPassword(passwordEncoder.encode(xhUsers.getPassword()));
                log.info("【用户修改】用户ID: {}, 密码已更新", xhUsers.getUserId());
            }
        } else {
            // 如果没有传递密码，则从数据库获取原密码
            XhUsers original = xhUsersService.selectXhUsersByUserId(xhUsers.getUserId());
            if (original != null) {
                xhUsers.setPassword(original.getPassword());
            }
        }
        int result = xhUsersService.updateXhUsers(xhUsers);
        log.info("【用户修改】用户ID: {}, 用户名: {}, 结果: {}", xhUsers.getUserId(), xhUsers.getUsername(), result > 0 ? "成功" : "失败");
        return toAjax(result);
    }

    /**
     * 删除用户管理
     */
    @PreAuthorize("@ss.hasPermi('system:users:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds) {
        int result = xhUsersService.deleteXhUsersByUserIds(userIds);
        log.info("【用户删除】删除 {} 个用户, 结果: {}", userIds.length, result > 0 ? "成功" : "失败");
        return toAjax(result);
    }

    /**
     * 微信登录
     */
    @Anonymous
    @ApiOperation(value = "微信登录", notes = "通过微信授权码进行登录认证")
    @PostMapping("/login-wechat")
    public R<Map<String, Object>> loginByWechat(@RequestBody WechatLoginDTO wechatLoginDTO) {
        String code = wechatLoginDTO.getCode();
        String nickname = wechatLoginDTO.getNickname();
        String avatarData = wechatLoginDTO.getAvatarData();

        log.info("操作=微信登录, 昵称={}", nickname);

        // 这里应该调用微信API获取用户openid，这里简化处理
        // 实际应用中应该使用 code 调用微信服务获取用户的 openid 和用户信息
        String openid = "wx_" + System.currentTimeMillis(); // 模拟openid

        // 查询用户是否存在
        XhUsers userParam = new XhUsers();
        userParam.setOpenid(openid);
        List<XhUsers> users = xhUsersService.selectXhUsersList(userParam);

        XhUsers user;
        if (users == null || users.isEmpty()) {
            // 用户不存在，自动注册
            log.info("操作=微信登录, 昵称={}, 结果=用户不存在，自动注册", nickname);
            user = new XhUsers();
            user.setOpenid(openid);
            user.setNickname(nickname);
            // 用户名设置为微信昵称+随机数
            user.setUsername(nickname + "_" + System.currentTimeMillis() % 10000);
            // 设置固定密码123456
            user.setPassword(passwordEncoder.encode("123456"));
            user.setStatus("0"); // 正常状态
            user.setTokens(100L); // 默认调用次数
            // 设置用户IP
            user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));

            // 保存头像
            if (avatarData != null && !avatarData.isEmpty()) {
                // 实际项目中应该保存到文件系统或云存储
                user.setAvatar(FileTool.saveAvatarToFile(avatarData, openid));
            }

            // 保存用户
            int result = xhUsersService.insertXhUsers(user);
            if (result <= 0) {
                log.error("操作=微信登录, 昵称={}, 结果=失败, 原因=注册失败", nickname);
                return R.fail(500, "登录失败，请稍后再试");
            }
        } else {
            user = users.get(0);
            log.info("操作=微信登录, 昵称={}, 结果=找到已注册用户, 用户ID={}", nickname, user.getUserId());

            // 更新昵称、头像和IP
            boolean needUpdate = false;
            if (nickname != null && !nickname.equals(user.getNickname())) {
                user.setNickname(nickname);
                needUpdate = true;
            }

            if (avatarData != null && !avatarData.isEmpty()) {
                user.setAvatar(FileTool.saveAvatarToFile(avatarData, openid));
                needUpdate = true;
            }
            
            // 更新用户IP
            user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
            needUpdate = true;

            if (needUpdate) {
                xhUsersService.updateXhUsers(user);
            }
        }

        // 创建登录用户对象
        LoginUser loginUser = UserTool.createLoginUser(user);
        // 生成token
        String token = tokenService.createToken(loginUser);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", user);

        log.info("操作=微信登录, 昵称={}, 结果=成功, 用户ID={}", nickname, user.getUserId());
        return R.ok(result, "登录成功");
    }

    /**
     * 用户头像上传
     */
    @ApiOperation(value = "修改头像", notes = "修改用户头像")
    @PostMapping("/upload-avatar")
    public R<XhUsers> uploadAvatar(@RequestBody AvatarDTO avatarDTO) {
        // 获取当前登录用户ID
        LoginUser loginUser = getLoginUser();
        if (loginUser == null) {
            return R.fail(401, "用户未登录或登录状态已过期");
        }

        Long userId = loginUser.getUserId();
        String base64Data = avatarDTO.getBase64Data();

        log.info("操作=头像上传, 用户ID={}", userId);

        if (base64Data == null || base64Data.isEmpty()) {
            log.warn("操作=头像上传, 用户ID={}, 结果=失败, 原因=头像数据为空", userId);
            return R.fail(400, "头像数据不能为空");
        }

        // 获取用户信息
        XhUsers user = xhUsersService.selectXhUsersByUserId(userId);
        if (user == null) {
            log.warn("操作=头像上传, 用户ID={}, 结果=失败, 原因=用户不存在", userId);
            return R.fail(404, "用户不存在");
        }

        // 保存头像
        String avatarPath = FileTool.saveAvatarToFile(base64Data, user.getOpenid() != null ? user.getOpenid() : userId.toString());
        user.setAvatar(avatarPath);

        // 更新用户信息
        int result = xhUsersService.updateXhUsers(user);

        if (result > 0) {
            log.info("操作=头像上传, 用户ID={}, 结果=成功", userId);
            return R.ok(user, "修改头像成功");
        } else {
            log.error("操作=头像上传, 用户ID={}, 结果=失败, 原因=数据库错误", userId);
            return R.fail(500, "头像更新失败，请稍后再试");
        }
    }

    /**
     * 获取用户信息
     */
    @ApiOperation(value = "获取当前用户信息", notes = "获取当前登录用户信息")
    @GetMapping("/info")
    public R<XhUsers> getUserInfo() {
        LoginUser loginUser = getLoginUser();
        if (loginUser == null) {
            return R.fail(401, "用户未登录或登录状态已过期");
        }

        Long userId = loginUser.getUserId();
        log.info("操作=获取用户信息, 用户ID={}", userId);

        XhUsers user = xhUsersService.selectXhUsersByUserId(userId);

        if (user == null) {
            log.warn("操作=获取用户信息, 用户ID={}, 结果=失败, 原因=用户不存在", userId);
            return R.fail(404, "用户不存在");
        }

        // 设置用户IP
        user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));

        // 脱敏处理
        user.setPassword(null);
        if (user.getMobile() != null) {
            user.setMobile(MobileTool.formatMobile(user.getMobile()));
        }

        log.info("操作=获取用户信息, 用户ID={}, 结果=成功", userId);
        return R.ok(user, "获取成功");
    }

    /**
     * 用户名密码登录
     */
    @Anonymous
    @ApiOperation(value = "用户名、密码登录", notes = "通过用户名和密码进行登录认证")
    @GetMapping("/login-username")
    public R<Map<String, Object>> loginByUsername(@Valid LoginUserDTO loginUserDTO) {
        log.info("操作=账号密码登录, 用户={}", loginUserDTO.getUsername());

        // 调用服务层方法进行用户验证
        XhUsers user = xhUsersService.loginByUsername(loginUserDTO.getUsername(), loginUserDTO.getPassword());

        if (user != null) {
            // 设置用户IP
            user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
            // 更新用户信息
            xhUsersService.updateXhUsers(user);
            
            // 创建登录用户对象
            LoginUser loginUser = UserTool.createLoginUser(user);
            // 生成token
            String token = tokenService.createToken(loginUser);

            // 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("user", user);

            log.info("操作=账号密码登录, 用户={}, 结果=成功, 用户ID={}", loginUserDTO.getUsername(), user.getUserId());
            return R.ok(result, "登录成功");
        } else {
            log.info("操作=账号密码登录, 用户={}, 结果=失败, 原因=用户名或密码错误", loginUserDTO.getUsername());
            return R.fail(400, "用户名或密码错误");
        }
    }

    /**
     * 发送手机验证码
     */
    @Anonymous
    @ApiOperation(value = "发送手机验证码", notes = "通过手机号获取验证码")
    @GetMapping("/mobile-send")
    public R<String> sendMobileVerificationCode(@Valid MobileDTO mobileDTO) {
        String mobile = mobileDTO.getMobile();
        log.info("操作=发送验证码, 手机号={}", MobileTool.formatMobile(mobile));

        // 检查手机号格式
        if (!MobileTool.isValid(mobile)) {
            log.warn("操作=发送验证码, 手机号={}, 结果=失败, 原因=格式错误", MobileTool.formatMobile(mobile));
            return R.fail(400, "手机号格式不正确");
        }

        // 检查是否频繁请求验证码
        if (VerificationCodeTool.isRequestFrequent(mobile)) {
            log.warn("操作=发送验证码, 手机号={}, 结果=失败, 原因=请求过于频繁", MobileTool.formatMobile(mobile));
            return R.fail(429, "请求过于频繁，请稍后再试");
        }

        // 生成6位随机数字验证码
        String code = VerificationCodeTool.generateCode();

        // 模拟存储验证码
        VerificationCodeTool.storeCode(mobile, code);

        // 格式化打印验证码(生产环境下应该通过短信服务发送)
        log.info("操作=发送验证码, 手机号={}, 结果=成功, 验证码={}, 有效期=10分钟", MobileTool.formatMobile(mobile), code);

        return R.ok("短信发送成功，10分钟内有效");
    }

    /**
     * 手机号登录-校验验证码
     */
    @Anonymous
    @ApiOperation(value = "手机号登录", notes = "通过手机号和验证码进行登录认证")
    @GetMapping("/login-mobile-verify")
    public R<Map<String, Object>> loginByMobileVerify(@Valid MobileVerifyDTO mobileVerifyDTO) {
        String mobile = mobileVerifyDTO.getMobile();
        String code = mobileVerifyDTO.getCode();

        log.info("操作=手机号登录, 手机号={}", MobileTool.formatMobile(mobile));

        // 验证验证码
        boolean isValid = VerificationCodeTool.verifyCode(mobile, code);
        if (!isValid) {
            log.warn("操作=手机号登录, 手机号={}, 结果=失败, 原因=验证码错误", MobileTool.formatMobile(mobile));
            return R.fail(201, "验证码错误或已过期，请重试");
        }

        // 查询用户是否存在
        XhUsers userParam = new XhUsers();
        userParam.setMobile(mobile);
        List<XhUsers> users = xhUsersService.selectXhUsersList(userParam);

        XhUsers user;
        if (users == null || users.isEmpty()) {
            // 用户不存在，自动注册
            log.info("操作=手机号登录, 手机号={}, 结果=用户不存在，自动注册", MobileTool.formatMobile(mobile));
            user = new XhUsers();
            user.setMobile(mobile);
            // 用户名设置为手机号
            user.setUsername(mobile);
            // 使用手机号作为默认昵称
            user.setNickname(mobile);
            // 设置固定密码123456
            user.setPassword(passwordEncoder.encode("123456"));
            user.setStatus("0"); // 正常状态
            user.setTokens(100L); // 默认调用次数
            // 设置用户IP
            user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));

            // 保存用户
            int result = xhUsersService.insertXhUsers(user);
            if (result <= 0) {
                log.error("操作=手机号登录, 手机号={}, 结果=失败, 原因=注册失败", MobileTool.formatMobile(mobile));
                return R.fail(500, "登录失败，请稍后再试");
            }
        } else {
            user = users.get(0);
            log.info("操作=手机号登录, 手机号={}, 结果=找到已注册用户, 用户ID={}", MobileTool.formatMobile(mobile), user.getUserId());
            
            // 更新用户IP
            user.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
            xhUsersService.updateXhUsers(user);
        }

        // 清除验证码
        VerificationCodeTool.clearCode(mobile);

        // 创建登录用户对象
        LoginUser loginUser = UserTool.createLoginUser(user);
        // 生成token
        String token = tokenService.createToken(loginUser);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", user);

        log.info("操作=手机号登录, 手机号={}, 结果=成功, 用户ID={}", MobileTool.formatMobile(mobile), user.getUserId());
        return R.ok(result, "登录成功");
    }

    /**
     * 手机号注册
     */
    @Anonymous
    @ApiOperation(value = "手机号注册", notes = "通过手机号和验证码进行注册")
    @PostMapping("/register-mobile")
    public R<XhUsers> registerByMobile(@Valid MobileVerifyDTO registerMobileDTO) {
        String mobile = registerMobileDTO.getMobile();
        String code = registerMobileDTO.getCode();

        log.info("操作=手机号注册, 手机号={}", MobileTool.formatMobile(mobile));

        // 验证验证码
        boolean isValid = VerificationCodeTool.verifyCode(mobile, code);
        if (!isValid) {
            log.warn("操作=手机号注册, 手机号={}, 结果=失败, 原因=验证码错误", MobileTool.formatMobile(mobile));
            return R.fail(201, "验证码错误或已过期，请重试");
        }

        // 查询用户是否存在
        XhUsers userParam = new XhUsers();
        userParam.setMobile(mobile);
        List<XhUsers> users = xhUsersService.selectXhUsersList(userParam);

        if (users != null && !users.isEmpty()) {
            log.warn("操作=手机号注册, 手机号={}, 结果=失败, 原因=手机号已注册", MobileTool.formatMobile(mobile));
            return R.fail(400, "手机号已注册");
        }

        // 创建新用户
        XhUsers newUser = new XhUsers();
        newUser.setMobile(mobile);
        // 用户名设置为手机号
        newUser.setUsername(mobile);
        // 昵称设置为手机号
        newUser.setNickname(mobile);
        // 设置固定密码123456
        newUser.setPassword(passwordEncoder.encode("123456"));
        newUser.setStatus("0"); // 正常状态
        newUser.setTokens(100L); // 默认调用次数
        // 设置用户IP
        newUser.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));

        // 保存用户
        int result = xhUsersService.insertXhUsers(newUser);

        if (result > 0) {
            // 清除验证码
            VerificationCodeTool.clearCode(mobile);

            log.info("操作=手机号注册, 手机号={}, 结果=成功, 用户ID={}", MobileTool.formatMobile(mobile), newUser.getUserId());
            return R.ok(newUser, "注册成功");
        } else {
            log.error("操作=手机号注册, 手机号={}, 结果=失败, 原因=数据库错误", MobileTool.formatMobile(mobile));
            return R.fail(500, "注册失败，请稍后再试");
        }
    }

    /**
     * 用户名密码注册
     */
    @Anonymous
    @ApiOperation(value = "用户名、密码注册", notes = "通过用户名和密码进行注册")
    @PostMapping("/register-username")
    public R<XhUsers> registerByUsername(@Valid LoginUserDTO registerDTO) {
        log.info("操作=用户名注册, 用户名={}", registerDTO.getUsername());

        // 检查用户名是否已存在
        XhUsers checkUser = new XhUsers();
        checkUser.setUsername(registerDTO.getUsername());
        List<XhUsers> existUsers = xhUsersService.selectXhUsersList(checkUser);

        if (existUsers != null && !existUsers.isEmpty()) {
            log.warn("操作=用户名注册, 用户名={}, 结果=失败, 原因=用户名已存在", registerDTO.getUsername());
            return R.fail(400, "用户名已存在");
        }

        // 创建新用户
        XhUsers newUser = new XhUsers();
        newUser.setUsername(registerDTO.getUsername());
        // 对密码进行BCrypt加密
        newUser.setPassword(passwordEncoder.encode(registerDTO.getPassword()));

        // 设置其他默认值
        newUser.setStatus("0"); // 正常状态
        newUser.setTokens(100L); // 默认调用次数
        // 使用用户名作为默认昵称
        newUser.setNickname(registerDTO.getUsername());
        // 设置用户IP
        newUser.setUserIp(IpUtils.getIpAddr(ServletUtils.getRequest()));

        // 保存用户
        int result = xhUsersService.insertXhUsers(newUser);

        if (result > 0) {
            log.info("操作=用户名注册, 用户名={}, 结果=成功, 用户ID={}", registerDTO.getUsername(), newUser.getUserId());
            return R.ok(newUser, "注册成功");
        } else {
            log.error("操作=用户名注册, 用户名={}, 结果=失败, 原因=数据库错误", registerDTO.getUsername());
            return R.fail(500, "注册失败，请稍后再试");
        }
    }
}